﻿using System;
using WalkingTec.Mvvm.Core;

namespace K9Nano.IM.Security
{
    public abstract class Md5SignModelManager<T> : ISignModelManager<T> where T : ISignModel
    {
        protected abstract string GetSecret(T model);

        protected virtual int ExpiresInSecond { get; set; } = 5;

        protected virtual string FormatSalt(string text, string salt)
        {
            return $"{text}&Secret={salt}";
        }

        public virtual long GetTimestamp()
        {
            return DateTimeOffset.Now.ToUnixTimeSeconds();
        }

        public virtual void Sign(T model)
        {
            if (model == null) throw new ArgumentNullException(nameof(model));

            model.Timestamp = GetTimestamp();

            var format = model.GetFormatString();

            var secret = GetSecret(model);

            if (string.IsNullOrEmpty(format))
            {
                model.Sign = string.Empty;
            }
            else
            {
                model.Sign = Utils.GetMD5String(FormatSalt(format, secret));
            }
        }

        public virtual bool Verify(T model)
        {
            if (model == null) throw new ArgumentNullException(nameof(model));

            var format = model.GetFormatString();

            var secret = GetSecret(model);

            if (string.IsNullOrEmpty(format))
            {
                return string.IsNullOrEmpty(model.Sign);
            }
            var sign = Utils.GetMD5String(FormatSalt(format, secret));

            if (string.Equals(sign, model.Sign))
            {
                var now = GetTimestamp();
                if (now - model.Timestamp <= ExpiresInSecond)
                {
                    return true;
                }
            }

            return false;
        }
    }
}